//; ---------------------------------------------------------------------------
//; Object (36) - Spikes
//; ---------------------------------------------------------------------------

#include "spikes.h"

#include "../sprite.h"
#include "../objectsystemNEWER.h"
#include "../collision.h"

static object *obj;

#define player objects[0]
extern object *objects;

extern byte v_invinc;

//; ---------------------------------------------------------------------------
//; Sprite mappings - spikes
//; ---------------------------------------------------------------------------
byte byte_CFF4[16] = { 3,			//; 3 spikes
		 0xF0,   3, 0, 4, 0xEC,
		 0xF0,   3, 0, 4, 0xFC,
		 0xF0,   3, 0, 4, 0xC
};
byte byte_D004[16] = { 3,			//; 3 spikes facing sideways
		 0xEC, 0xC, 0, 0, 0xF0,
		 0xFC, 0xC, 0, 0, 0xF0,
		  0xC, 0xC, 0, 0, 0xF0
};
byte byte_D014[6] =  { 1,			//; 1 spike
		 0xF0,   3, 0, 4, 0xFC
};
byte byte_D01A[16] = { 3,			//; 3 spikes widely spaced
		 0xF0,   3, 0, 4, 0xE4,
		 0xF0,   3, 0, 4, 0xFC,
		 0xF0,   3, 0, 4, 0x14
};
byte byte_D02A[31] = { 6,			//; 6 spikes
		 0xF0,   3, 0, 4, 0xC0,
		 0xF0,   3, 0, 4, 0xD8,
		 0xF0,   3, 0, 4, 0xF0,
		 0xF0,   3, 0, 4,    8,
		 0xF0,   3, 0, 4, 0x20,
		 0xF0,   3, 0, 4, 0x38
};
byte byte_D049[6] = { 1,			//; 1 spike facing sideways
		 0xFC, 0xC, 0, 0, 0xF0
};

byte *Map_Spike[6] = { byte_CFF4, byte_D004, byte_D014, byte_D01A, byte_D02A, byte_D049 };
//==========

void (*Spik_Index[2])() = { Spik_Main, Spik_Solid };

//Spikes:					; XREF: Obj_Index
void Spikes(object *_obj)
{
    obj = _obj;

    //moveq	#0,d0
    //move.b	obRoutine(a0),d0
    byte routine = obj->Routine/2;

    //move.w	Ring_Index(pc,d0.w),d1
    //jmp	Ring_Index(pc,d1.w)
    (*Spik_Index[routine])();
}

//; ===========================================================================


#define spik_origX 0x30		//; start X position
#define spik_origY 0x32		//; start Y position

byte Spik_Var[12] = { 0, 0x14,	//; frame number,	object width
		      1, 0x10,
		      2,    4,
		      3, 0x1C,
		      4, 0x40,
		      5, 0x10
};

//Spik_Main:	; Routine 0
void Spik_Main()
{
    //Spik_Main:	; Routine 0
    //addq.b	#2,obRoutine(a0)
    obj->Routine = obj->Routine + 2;
	
    //move.l	#Map_Spike,obMap(a0)
    obj->Map = Map_Spike;

    //move.w	#$51B,obGfx(a0)
    obj->Gfx = 0x51B;
	
    //ori.b	#4,obRender(a0)
    obj->Render = obj->Render | 4;
	
    //move.b	#4,obPriority(a0)
    obj->Priority = 4;
	
    //move.b	obSubtype(a0),d0
    byte spikeAttr = obj->Subtype;
	
    //andi.b	#$F,obSubtype(a0)
    obj->Subtype = obj->Subtype & 0xF;
	
    //andi.w	#$F0,d0
    //lea	(Spik_Var).l,a1
    //lsr.w	#3,d0
    word spikeType = (spikeAttr & 0xF0) >> 3;

    //adda.w	d0,a1
    byte *spikeVars = &Spik_Var[spikeType];
    
    //move.b	(a1)+,obFrame(a0)
    obj->Frame = *(spikeVars++);

    //move.b	(a1)+,obActWid(a0)
    obj->ActionWidth = *(spikeVars++);

    //move.w	obX(a0),spik_origX(a0)
    ptrsetobjvariableword(spik_origX, obj, obj->X);

    //move.w	obY(a0),spik_origY(a0)
    ptrsetobjvariableword(spik_origY, obj, obj->Y);

    Spik_Solid();
}

//; ===========================================================================


//; ===========================================================================



//Spik_Solid:	; Routine 2
void Spik_Solid()
{
    //bsr.w	Spik_Type0x	; make the object move
    Spik_Type0x();

    //move.w	#4,d2
    word jumpHeight = 4;		

    //cmpi.b	#5,obFrame(a0)	; is object type $5x ?
    //beq.s	Spik_SideWays	; if yes, branch
    //cmpi.b	#1,obFrame(a0)	; is object type $1x ?
    //bne.s	Spik_Upright	; if not, branch
    //move.w	#$14,d2

    if (obj->Frame == 5 || (obj->Frame == 1) ) 
    {	
        if (obj->Frame == 1) { jumpHeight = 20; }
        
        //; Spikes types $1x and $5x face	sideways
        //Spik_SideWays:				; XREF: Spik_Solid
	//move.w	#$1B,d1
        word spikeWidth = 27;

	//move.w	d2,d3
        //addq.w	#1,d3
        word walkHeight = jumpHeight + 1;

	//move.w	obX(a0),d4
        word xpos = obj->X;

	//bsr.w	SolidObject
        long hitSpikes = SolidObject(obj, spikeWidth, jumpHeight, walkHeight, xpos);

	//btst	#3,obStatus(a0)
        //bne.s	Spik_Display
        //cmpi.w	#1,d4
	//beq.s	Spik_Hurt
        if ((obj->Status & 8) == 8) { Spik_Display(); }
	else if (hitSpikes == 1) { Spik_Hurt(); }	
        else { Spik_Display(); }
    }  
    else
    {
        //; Spikes types $0x, $2x, $3x and $4x face up or	down

        //Spik_Upright:				; XREF: Spik_Solid
	//moveq	#0,d1
	//move.b	obActWid(a0),d1
	//addi.w	#$B,d1
        word spikeWidth = obj->ActionWidth + 11;

	//move.w	#$10,d2
        word walkHeight = 16;

	//move.w	#$11,d3
        word jumpHeight = 17;

	//move.w	obX(a0),d4
        word xpos = obj->X;

	//bsr.w	SolidObject
        long hitSpikes = SolidObject(obj, spikeWidth, jumpHeight, walkHeight, xpos);

	//btst	#3,obStatus(a0)
	//bne.s	Spik_Hurt
        //tst.w	d4
	//bpl.s	Spik_Display
        if ((obj->Status & 8) == 8) { Spik_Hurt(); }
        else if (hitSpikes >= 0) { Spik_Display(); }
        else { Spik_Hurt(); }

    }
}

//Spik_Hurt:				; XREF: Spik_SideWays; Spik_Upright
void Spik_Hurt()
{
    //tst.b	(v_invinc).w	; is Sonic invincible?
    //bne.s	Spik_Display	; if yes, branch
    if (v_invinc!=0) { Spik_Display(); }
    else
    { 	
        //move.l	a0,-(sp)
	//movea.l	a0,a2
	//lea	(v_player).w,a0
        //cmpi.b	#4,obRoutine(a0)
	//bcc.s	loc_CF20
        if (player.Routine >= 4)
        {
	    //move.l	obY(a0),d3
            long playerY = player.Y;

            //move.w	obVelY(a0),d0	; load vertical	speed
            signed short playerVelY = player.VelocityY;
   
            //ext.l	d0
            //asl.l	#8,d0		; multiply by $100
            signed long playerShiftY = playerVelY * 0x100; 

            //sub.l	d0,d3		; subtract from y-axis	position
            long newY = playerY - playerShiftY;

	    //move.l	d3,obY(a0)
            player.Y = newY;

	    //jsr	HurtSonic
            //HurtSonic();
        }
        else
        {
            //loc_CF20:
	    //movea.l	(sp)+,a0
            
            Spik_Display();        
        }
    }
}

//Spik_Display:
void Spik_Display()
{
    //bsr.w	DisplaySprite
    DisplaySprite(obj);

    //out_of_range	DeleteObject,spik_origX(a0)
    if (out_of_range(ptrgetobjvariableword(spik_origX, obj))) { DeleteObject(obj); }

}   //rts	

//; ===========================================================================

void (*Spik_TypeIndex[3])() = { Spik_Type00, Spik_Type01, Spik_Type02 };

//Spik_Type0x:				; XREF: Spik_Solid
void Spik_Type0x()
{
    //moveq	#0,d0
    //move.b	obSubtype(a0),d0
    //add.w	d0,d0
    byte spikeMoveRoutine = obj->Subtype * 2;

    //move.w	Spik_TypeIndex(pc,d0.w),d1
    //jmp	Spik_TypeIndex(pc,d1.w)
    (*Spik_TypeIndex[spikeMoveRoutine])();
}

//Spik_Type00:				; XREF: Spik_TypeIndex
void Spik_Type00()
{
    //rts			; don't move the object

}   //; ===========================================================================

//Spik_Type01:				; XREF: Spik_TypeIndex
void Spik_Type01()
{
    //bsr.w	Spik_Wait
    Spik_Wait();

    //moveq	#0,d0
    //move.b	$34(a0),d0
    signed char moveDist = obj->Variables[0x34-0x28];

    //add.w	spik_origY(a0),d0
    signed short newY = ptrgetobjvariableword(spik_origY, obj) + moveDist;

    //move.w	d0,obY(a0)	; move the object vertically
    obj->Y = newY;
}    //rts

	
//; ===========================================================================

//Spik_Type02:				; XREF: Spik_TypeIndex
void Spik_Type02()
{
    //bsr.w	Spik_Wait
    Spik_Wait();

    //moveq	#0,d0
    //move.b	$34(a0),d0
    signed char moveDist = obj->Variables[0x34-0x28];

    //add.w	spik_origX(a0),d0
    signed short newX = ptrgetobjvariableword(spik_origX, obj) + moveDist;

    //move.w	d0,obX(a0)	; move the object horizontally
    obj->X = newX;
}    //rts

//; ===========================================================================

//Spik_Wait:
void Spik_Wait()
{
    //tst.w	$38(a0)		; is time delay	= zero?
    //beq.s	loc_CFA4	; if yes, branch
    if (ptrgetobjvariableword(0x38, obj) != 0)
    {
        //subq.w	#1,$38(a0)	; subtract 1 from time delay
        ptrsubobjvariableword(0x38, obj, 1);

	//bne.s	locret_CFE6
        if (ptrgetobjvariableword(0x38, obj) == 0)
        {
	    //tst.b	obRender(a0)
            //bpl.s	locret_CFE6
            if (obj->Render > 0x80)
            {
	        //sfx	sfx_SpikesMove	; play "spikes moving" sound
		//bra.s	locret_CFE6
            }
        }
    }
    else
    {
        //; ===========================================================================
        //loc_CFA4:
	//tst.w	$36(a0)
        //beq.s	loc_CFC6
        if (ptrgetobjvariableword(0x36, obj) != 0)
        {
	    //subi.w	#$800,$34(a0)
            ptrsubobjvariableword(0x34, obj, 0x800);

	    //bcc.s	locret_CFE6
            if ((signed short)ptrgetobjvariableword(0x34, obj) < 0)
            {
	        //move.w	#0,$34(a0)
                ptrsetobjvariableword(0x34, obj, 0);

		//move.w	#0,$36(a0)
                ptrsetobjvariableword(0x36, obj, 0);

		//move.w	#60,$38(a0)	; set time delay to 1 second
                ptrsetobjvariableword(0x38, obj, 60);

		//bra.s	locret_CFE6
                //; ===========================================================================
            }
        }
        else
        {
            //loc_CFC6:
	    //addi.w	#$800,$34(a0)
            ptraddobjvariableword(0x34, obj, 0x800);

	    //cmpi.w	#$2000,$34(a0)
            //bcs.s	locret_CFE6
            if (ptrgetobjvariableword(0x34, obj) > 0x2000)
            {
		//move.w	#$2000,$34(a0)
                ptrsetobjvariableword(0x34, obj, 0x2000);

		//move.w	#1,$36(a0)
                ptrsetobjvariableword(0x36, obj, 1);

		//move.w	#60,$38(a0)	; set time delay to 1 second
                ptrsetobjvariableword(0x38, obj, 60);
            }
            
        }
    }
    //locret_CFE6:
    //rts	
}
